/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年7月25日
 * 项目： rainhy-minitools
 */
package com.rainhy.minitools.sudoku;

import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.MapUtils;

/**
 * 数独<br>
 * 以数独左上角为坐标系原点(0,0),右下角为坐标系(8,8)点,其它点以此类推
 * 
 * @author rain
 * @version [版本号, 2016年7月25日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class Sudoku implements Serializable {
    private static final long serialVersionUID = 2801756752884056939L;
    
    /** 不能填充的格子 */
    private Set<Grid> notFillList = new HashSet<>();
    
    /** 棋盘(全部行)(y,row) */
    private Map<Integer, Row> rowMap = new HashMap<>();
    
    /** 棋盘(全部列)(x,col) */
    private Map<Integer, Col> colMap = new HashMap<>();
    
    /** 棋盘(全部井)(xWell,(yWell,well)) */
    private Map<Integer, Map<Integer, Well>> wellMap = new HashMap<>();
    
    public Sudoku() {
        super();
        init();
    }
    
    /** 把数独转换成字符串(从左至右,从上至下的转换) */
    public String converToString() {
        StringBuilder sb = new StringBuilder();
        for (int y = 0; y < 9; y++) {
            Row row = this.rowMap.get(Integer.valueOf(y));
            for (int x = 0; x < 9; x++) {
                sb.append(row.getGrid(x).getValue());
            }
        }
        return sb.toString();
    }
    
    /** 返回行集合 */
    public Map<Integer, Row> getRowMap() {
        return this.rowMap;
    }
    
    /**
     * 
     * 初始化数独<br>
     * 每个数字字符为一个有效字符,从左至右,从上至下进行数独格子填充(1~9为有效填充,非1~9填充0)<br>
     * 如果长度不够,则剩余全部填充为0<br>
     * 遇到无效字符,自动跳过.
     *
     * @param sudoku
     * 
     * @return void [返回类型说明]
     * @exception throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     * @version [版本号, 2016年7月25日]
     * @author rain
     */
    public void init(String sudoku) {
        char[] charArray = sudoku.toCharArray();
        int index = 0;
        for (char c : charArray) {
            if ('0' <= c && c <= '9') {
                fill(index % 9, index++ / 9, Integer.valueOf(String.valueOf(c)).intValue());
            }
        }
    }
    
    /** 填充格子(主要是格子里面的值) */
    private Grid fill(int x, int y, int value) {
        Grid grid = getGrid(x, y);
        grid.fill(value);
        this.colMap.get(x).refresh(grid);
        this.rowMap.get(y).refresh(grid);
        getWell(x, y).refresh(grid);
        this.notFillList.add(grid);
        return grid;
    }
    
    /** 根据坐标获取格子 */
    private Grid getGrid(int x, int y) {
        return this.rowMap.get(y).getGrid(x);
    }
    
    /** 传入九宫格坐标,返回对应坐标上的井字格(小九宫格) */
    private Well getWell(int x, int y) {
        return this.wellMap.get(x / 3).get(y / 3);
    }
    
    /** 初始化"初始"数据 */
    @SuppressWarnings("unchecked")
    private void init() {
        ///// 棋盘(全部行),棋盘(全部列),棋盘(全部井)
        for (int i = 0; i < 9; i++) {
            this.rowMap.put(i, new Row(i));
            this.colMap.put(i, new Col(i));
        }
        for (int x = 0; x < 3; x++) {
            Map<Integer, Well> yWellMap = new HashMap<>();
            this.wellMap.put(x, yWellMap);
            for (int y = 0; y < 3; y++) {
                yWellMap.put(y, new Well(x, y));
            }
        }
        
        ///// 棋盘(全部格子)
        for (int x = 0; x < 9; x++) {
            for (int y = 0; y < 9; y++) {
                Grid grid = new Grid(x, y);
                this.rowMap.get(y).init(grid);
                this.colMap.get(x).init(grid);
                getWell(x, y).init(grid);
            }
        }
        
        ///// 不可变 map
        this.rowMap = MapUtils.unmodifiableMap(this.rowMap);
        this.colMap = MapUtils.unmodifiableMap(this.colMap);
        this.wellMap = MapUtils.unmodifiableMap(this.wellMap);
    }
}
